home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 050 / lisp.pas < prev    next >
Pascal/Delphi Source File  |  1985-05-27  |  23KB  |  831 lines

  1. program LISP;
  2.  
  3. {
  4.   The essence of a LISP Interpreter.
  5.   written by W. Taylor and L. Cox
  6.   First date started : 10/29/76
  7.   Last date modified : 12/10/76
  8.   Modified for TURBO by R. Stearns, M. Covington
  9.   Date started       : 05/21/85
  10.   Date finished      : 05/21/85
  11.   Modified for readability by R. Stearns
  12.   Date started       : 05/22/85
  13.   Date finished      :
  14. }
  15.  
  16. const
  17.      maxnode = 1000;
  18.  
  19. type
  20.      longstr       = string[255];
  21.      inputsymbol   = (atom, period, lparen, rparen);
  22.      reservedwords =
  23.          (replacehsym, replacetsym, headsym, tailsym, eqsym, quotesym,
  24.           atomsym, condsym, labelsym, lambdasym, copysym, appendsym, concsym,
  25.           conssym);
  26.      statustype    = (unmarked, left, right, marked);
  27.      symbexpptr    = ^symbolicexpression;
  28.      alfa          = array [1 .. 10] of char;
  29.      symbolicexpression = record
  30.           status : statustype;
  31.           next   : symbexpptr;
  32.           case anatom  : boolean of
  33.                  true  : (name : alfa;
  34.                           case isareservedword : boolean of
  35.                                true : (ressym : reservedwords));
  36.                  false : (head, tail : symbexpptr)
  37.           end;
  38. {
  39.   Symbolicexpression is the record structure used
  40.   to implement a LISP list.  This record has a tag
  41.   field 'anatom' which tells which kind of node
  42.   a particular node represents (i.e. an atom or
  43.   a pair of pointers 'head' and 'tail').
  44.   'Anatom' is always checked before accessing
  45.   either the name field or the head and tail
  46.   fields of a node.  Two pages ahead there are
  47.   three diagrams which should clarify the data
  48.   structure.
  49. }
  50.  
  51. {            T h e  g l o b a l  v a r i a b l e s                           }
  52.  
  53. var
  54.  
  55. {  Variables which pass information from the scanner to the read routine.    }
  56.  
  57.   lookaheadsym,                {  used to save a symbol when we back up      }
  58.   sym           : inputsymbol; {  the symbol that was last scanned           }
  59.   id            : alfa;        {  name of atom that was last read            }
  60.   alreadypeeked : boolean;     {  tells 'nextsym' whether we haved peeked    }
  61.   ch            : char;        {  the last character read from input         }
  62.   curline       : longstr;     {  the current input line                     }
  63.   ptr           : symbexpptr;  {  the pointer to expression being evaluated  }
  64.  
  65.          {  the global lists of LISP nodes  }
  66.   freelist,                    {  pointer to the linear list of free nodes   }
  67.   nodelist,                    {  pointer used to make a linear scan of all  }
  68.                                {  the nodes during garbage collection        }
  69.   alist         : symbexpptr;  {                                             }
  70.  
  71. {  two nodes which have constant values                                      }
  72.  
  73.   nilnode,
  74.   tnode         : symbolicexpression;
  75.  
  76. {  variables used to identify atoms with pre-defined meanings                }
  77.  
  78.   resword       : reservedwords;
  79.   reserved      : boolean;
  80.   reswords      : array [reservedwords] of alfa;
  81.   freenodes     : integer;     {  number of currently free nodes known      }
  82.   numberofgcs   : integer;     {  number of garbage collections made        }
  83.  
  84. {  The function trim and procedure getch provided to circumvent some of the }
  85. {  peculiarities of TURBO Pascal terminal I/O                               }
  86.  
  87. {  This function returns its argument with all trailing blanks removed      }
  88.  
  89. function trim(s: longstr) : longstr;
  90.  
  91. var
  92.      i     : integer;
  93.  
  94. begin
  95.      i := length(s);
  96.      while((i>0) and (s[i]=' ')) do i := i-1;
  97.      trim := copy(s,1,i);
  98. end;
  99.  
  100. {  This procedure returns, in ch, the next character of input from the kbd  }
  101.  
  102. procedure getch(var ch : char);
  103.  
  104. begin
  105.      while (curline='') do begin
  106.           write('? ');
  107.           readln(curline);
  108.           curline := trim(curline)+' ';
  109.      end;
  110.      ch := upcase(curline[1]);
  111.      curline := copy(curline,2,length(curline)-1);
  112. end;
  113.  
  114. procedure garbageman;
  115.  
  116.   procedure mark(list : symbexpptr);
  117.  
  118.     var
  119.       father, son, current : symbexpptr;
  120.  
  121.     begin
  122.       father := nil;
  123.       current := list;
  124.       son := current;
  125.       while current <> nil do
  126.         with current^ do
  127.           case status of
  128.             unmarked:
  129.               if anatom  then  status := marked
  130.               else
  131.                 if (head^.status <> unmarked) or (head = current)
  132.                 then
  133.                   if (tail^.status <> unmarked) or (tail = current)
  134.                   then status := marked
  135.                   else
  136.                     begin
  137.                       status := right;
  138.                       son := tail;
  139.                       tail := father;
  140.                       father := current;
  141.                       current := son
  142.                     end
  143.                 else
  144.                   begin
  145.                     status := left;
  146.                     son := head;
  147.                     head := father;
  148.                     father := current;
  149.                     current := son
  150.                   end;
  151.             left:
  152.               if tail^.status <> unmarked
  153.               then
  154.                 begin
  155.                   status := marked;
  156.                   father := head;
  157.                   head := son;
  158.                   son := current
  159.                 end
  160.               else
  161.                 begin
  162.                   status := right;
  163.                   current := tail;
  164.                   tail := head;
  165.                   head := son;
  166.                   son := current
  167.                 end;
  168.             right:
  169.               begin
  170.                 status := marked;
  171.                 father := tail;
  172.                 tail := son;
  173.                 son := current
  174.               end;
  175.             marked:  current := father
  176.           end { case }
  177.         end; { mark }
  178.  
  179.         procedure collectfreenodes;
  180.  
  181.           var
  182.             temp : symbexpptr;
  183.  
  184.           begin
  185.             writeln(' Number of nodes before collection = ', freenodes:1,'.');
  186.             freelist := nil;
  187.             freenodes := 0;
  188.             temp := nodelist;
  189.             while temp <> nil do
  190.               begin
  191.                 if temp^.status <> unmarked then temp^.status := unmarked
  192.                 else
  193.                   begin
  194.                     freenodes := freenodes + 1;
  195.                     temp^.head := freelist;
  196.                     freelist := temp
  197.                   end;
  198.                 temp := temp^.next
  199.               end;
  200.             writeln(' Number of nodes after collection = ', freenodes:1,'.');
  201.           end;  { collectfreenodes  }
  202.  
  203.   begin  { garbageman }
  204.     numberofgcs := numberofgcs + 1;
  205.     writeln;
  206.     writeln(' Garbage collection. ');
  207.     writeln;
  208.     mark(alist);
  209.     if ptr <> nil then mark(ptr);
  210.     collectfreenodes
  211.   end;  { grabageman }
  212.  
  213. procedure pop(var sptr : symbexpptr);
  214.  
  215.   begin
  216.     if freelist = nil then
  217.       begin
  218.         writeln(' Not enough space to evaluate the expression.');
  219.       end;
  220.     freenodes := freenodes - 1;
  221.     sptr := freelist;
  222.     freelist := freelist^.head
  223.   end; { pop }
  224.  
  225.  
  226. {  i n p u t  /  o u t p u t  u t i l i t y  r o u t i n e s   }
  227.  
  228. procedure error(numbers : integer);
  229.  
  230.   begin
  231.     writeln;
  232.     write(' Error   ',numbers:1,',');
  233.     case numbers of
  234.       1 : writeln(' atom or lparen expected in the s-expr.');
  235.       2 : writeln(' atom, lparen, or rparen expected in the s-expr.');
  236.       3 : writeln(' label and lambda are not names of functions.');
  237.       4 : writeln(' rparen expected in the s-expr.');
  238.       5 : writeln(' 1st argument of replaceh is an atom.');
  239.       6 : writeln(' 1st argument of replacet is an atom.');
  240.       7 : writeln(' argument of head is an atom.');
  241.       8 : writeln(' argument of tail is an atom.');
  242.       9 : writeln(' 1st argument of append is not a list.');
  243.      10 : writeln(' comma or rparen expected in concatenate.');
  244.      11 : writeln(' end of file encountered before a "fin" card.');
  245.      12 : writeln(' lambda or label expected.')
  246.     end;  { case }
  247.     halt;
  248.   end;  { error }
  249.  
  250. {
  251.   procedure backupinput puts a left parenthesis
  252.   into the stream of input symbols.  this makes
  253.   procedure readexpr easier than it otherwise
  254.   would be.
  255. }
  256.  
  257. procedure backupinput;
  258.  
  259.   begin
  260.     alreadypeeked := true;
  261.     lookaheadsym := sym;
  262.     sym := lparen
  263.   end;  { backupinput }
  264.  
  265. procedure nextsym;
  266.  
  267.   var
  268.     i : integer;
  269.  
  270.   begin
  271.     if alreadypeeked then
  272.       begin
  273.          sym := lookaheadsym;
  274.          alreadypeeked := false
  275.       end
  276.     else
  277.       begin
  278.         while ch = ' ' do getch(ch);
  279.         if ch in ['(','.',')'] then
  280.           begin
  281.             case ch of
  282.                '(' : sym := lparen;
  283.                '.' : sym := period;
  284.                ')' : sym := rparen
  285.             end; { case }
  286.             getch(ch);
  287.           end
  288.         else
  289.           begin
  290.             sym := atom;
  291.             id := '          ';
  292.             i := 0;
  293.             repeat
  294.               i := i + 1;
  295.               if i < 11 then id[i] := ch;
  296.               getch(ch);
  297.             until ch in [' ', '(', '.', ')'];
  298.             resword := replacehsym;
  299.             while (id <> reswords[resword]) and (resword <> conssym) do
  300.               resword := succ(resword);
  301.             reserved := (id = reswords[resword])
  302.           end
  303.         end
  304.   end;  { nextsym }
  305.  
  306. procedure readexpr(var sptr : symbexpptr);
  307.  
  308.   var
  309.     nxt : symbexpptr;
  310.  
  311.   begin
  312.     pop(sptr);
  313.     nxt := sptr^.next;
  314.     case sym of
  315.       rparen,
  316.       period  : error(1);
  317.       atom    : with sptr^ do
  318.           begin  { <atom> }
  319.             anatom := true;
  320.             name := id;
  321.             isareservedword := reserved;
  322.             if reserved then ressym := resword
  323.           end;
  324.       lparen : with sptr^ do
  325.           begin
  326.             nextsym;
  327.             if sym = period then error(2)
  328.             else
  329.               if sym = rparen then sptr^ := nilnode  {  () = nil }
  330.               else
  331.                 begin
  332.                   anatom := false;
  333.                   readexpr(head);
  334.                   nextsym;
  335.                   if sym = period then
  336.                     begin
  337.                       nextsym;
  338.                       readexpr(tail);
  339.                       nextsym;
  340.                       if sym <> rparen then error(4)
  341.                     end
  342.                   else
  343.                     begin  {  (<s-expr> <s-expr> ... <s-expr> )  }
  344.                       backupinput;
  345.                       readexpr(tail)
  346.                     end
  347.                  end
  348.           end { with }
  349.        end;  { case }
  350.        sptr^.next := nxt
  351.   end; { readexpr }
  352.  
  353. procedure printname(name : alfa);
  354. {
  355.   procedure printname prints the name of
  356.   an atom with one trailing blank.
  357. }
  358.  
  359. var
  360.   i : integer;
  361.  
  362. begin
  363.   i := 1;
  364.   repeat
  365.     write(name[i]);
  366.     i := i + 1;
  367.   until (name[i] = ' ') or (i = 11);
  368.   write(' ')
  369. end; { printname }
  370.  
  371. procedure printexpr(sptr : symbexpptr);
  372. {
  373.   The algorithm for this procedure was provided by
  374.   Weissman's LISP 1.5 primer, p 125.  This procedure
  375.   prints the symbolic expression pointed to by the
  376.   argument 'sptr' in the LISP list notation.
  377. }
  378.  
  379. label
  380.   1;
  381.  
  382. begin
  383.   if sptr^.anatom then printname(sptr^.name)
  384.   else
  385.     begin
  386.       write('(');
  387.     1: with sptr^ do
  388.          begin
  389.            printexpr(head);
  390.            if tail^.anatom and (tail^.name = 'NIL       ')
  391.            then write(')')
  392.            else
  393.              if tail^.anatom then
  394.                begin
  395.                   write('.');
  396.                   printexpr(tail);
  397.                   write(')')
  398.                end
  399.              else
  400.                begin
  401.                   sptr := tail;
  402.                   goto 1
  403.                end
  404.          end
  405.      end
  406. end; { printexpr }
  407.  
  408. {         e n d  o f  i / o  u t i l i t y  r o u t i n e s        }
  409.  
  410. {      T h e  e x p r e s s i o n  e v a l u a t e r  e v a l      }
  411.  
  412. function eval(e, alist : symbexpptr) : symbexpptr;
  413. {
  414.      evaluate 'e' using the association list 'alist'
  415.  
  416.      (lambda (e alist)
  417.        cond
  418.          ((atom e) (lookup e alist))
  419.          ((atom (car e))
  420.             (cond ((eq (car e) (quote quote))
  421.                 (cadr e))
  422.               ((eq (car e) (quote atom))
  423.                 (atom (eval (cadr e) alist)
  424.               ((eq (car e) (quote eq))
  425.                 (eq (eval (cadr e) alist)))
  426.               ((eq (car e) (quote car))
  427.                 (car (eval (cadr e) alist)))
  428.               ((eq (car e) (quote cdr))
  429.                 (cdr (eval (cadr e) alist)))
  430.               ((eq (car e) (quote cons)
  431.                 (cons (eval (cadr e) alist)
  432.                   (eval (caddr e) alist)
  433.               ((eq (car e) (quote cond)
  434.                 (evcon (cdr e))
  435.               (t (eval (cons (lookup (car e) alist)
  436.                 (cdr e)) alist)))
  437.               ((eq (caar e) (quote label))
  438.                 (eval (cons (caddar e)
  439.                 (cdr e)
  440.                 (cons (cons (cadar e) (car e))
  441.                   alist) ))
  442.              ((eq (caar e) (quote lambda))
  443.                (eval (caddr e)
  444.                  (bindargs (cadar e) (cdr e) )))))
  445.  
  446.       The resulting Pascal code follows:
  447. }
  448.  
  449. var
  450.   temp,
  451.   carofe,
  452.   caarofe      : symbexpptr;
  453.  
  454. {
  455.   The first ten of the following local functions implement
  456.   ten LISP primitives.  The last three are used by eval.
  457. }
  458.  
  459.   function replaceh(sptr1, sptr2 : symbexpptr) : symbexpptr;
  460.  
  461.     begin
  462.       if sptr1^.anatom then error(5)  else sptr1^.head := sptr2;
  463.       replaceh := sptr1
  464.     end;  { replaceh }
  465.  
  466.   function replacet(sptr1, sptr2 : symbexpptr) : symbexpptr;
  467.  
  468.     begin
  469.       if sptr1^.anatom then error(6)  else sptr1^.tail := sptr2;
  470.       replacet := sptr1
  471.     end;  { replacet }
  472.  
  473.   function head(sptr : symbexpptr) : symbexpptr;
  474.  
  475.     begin
  476.       if sptr^.anatom  then error(7)  else head := sptr^.head
  477.     end;  { head }
  478.  
  479.   function tail(sptr : symbexpptr) : symbexpptr;
  480.  
  481.     begin
  482.       if sptr^.anatom then error(8)  else  tail := sptr^.tail
  483.     end;  { tail }
  484.  
  485.   function cons(sptr1, sptr2 : symbexpptr) : symbexpptr;
  486.  
  487.     var
  488.       temp : symbexpptr;
  489.  
  490.     begin
  491.       pop(temp);
  492.       temp^.anatom := false;
  493.       temp^.head := sptr1;
  494.       temp^.tail := sptr2;
  495.       cons := temp
  496.     end;  { cons }
  497.  
  498.   function copy(sptr : symbexpptr) : symbexpptr;
  499.  
  500.   {
  501.      This function creates a copy of the structure
  502.      pointed to by the parameter 'sptr'
  503.   }
  504.  
  505.   var
  506.     temp,
  507.     nxt          : symbexpptr;
  508.  
  509.   begin
  510.     if sptr^.anatom then
  511.       begin
  512.         pop(temp);
  513.         nxt := temp^.next;
  514.         temp^ := sptr^;
  515.         temp^.next := nxt;
  516.         copy := temp
  517.       end
  518.     else  copy := cons(copy(sptr^.head), copy(sptr^.tail))
  519.   end;  { copy }
  520.  
  521.   function append(sptr1, sptr2 : symbexpptr) : symbexpptr;
  522.  
  523.   {
  524.       The recursive algorithym is from Weissman, p. 97.
  525.   }
  526.  
  527.   begin
  528.     if sptr1^.anatom then
  529.       if sptr1^.name <> 'NIL       ' then error(9)
  530.       else  append := sptr2
  531.     else
  532.       append := cons(copy(sptr1^.head), append(sptr1^.tail, sptr2))
  533.   end; { append }
  534.  
  535.   function conc(sptr1 : symbexpptr) : symbexpptr;
  536.  
  537.   var
  538.     sptr2,
  539.     nilptr        : symbexpptr;
  540.  
  541.   begin
  542.     if sym <> rparen then
  543.       begin
  544.         nextsym;
  545.         readexpr(sptr2);
  546.         nextsym;
  547.         conc := cons(sptr1, conc(sptr2));
  548.       end
  549.     else
  550.       if sym = rparen then
  551.           begin
  552.             new(nilptr);
  553.             with nilptr^ do begin
  554.                anatom := true;
  555.                name := 'NIL       '
  556.                end;
  557.             conc := cons(sptr1, nilptr);
  558.           end
  559.       else error(10)
  560.   end;  { conc }
  561.  
  562.   function eqq(sptr1, sptr2 : symbexpptr) : symbexpptr;
  563.  
  564.   var
  565.     temp,
  566.     nxt         : symbexpptr;
  567.  
  568.   begin
  569.     pop(temp);
  570.     nxt := temp^.next;
  571.     if sptr1^.anatom and sptr2^.anatom then
  572.       if sptr1^.name = sptr2^.name  then temp^ := tnode
  573.       else temp^ := nilnode
  574.     else
  575.       if sptr1 = sptr2  then temp^ := tnode
  576.       else temp^ := nilnode;
  577.     temp^.next := nxt;
  578.     eqq := temp
  579.   end; { eqq }
  580.  
  581.   function atom(sptr : symbexpptr) : symbexpptr;
  582.  
  583.   var
  584.     temp,
  585.     nxt       : symbexpptr;
  586.  
  587.   begin
  588.     pop(temp);
  589.     nxt := temp^.next;
  590.     if sptr^.anatom  then temp^ := tnode  else temp^ := nilnode;
  591.     temp^.next := nxt;
  592.     atom := temp
  593.   end; { atom }
  594.  
  595.   function lookup(key, alist : symbexpptr) : symbexpptr;
  596.  
  597.   var
  598.     temp : symbexpptr;
  599.  
  600.   begin
  601.     temp := eqq(head(head(alist)), key);
  602.     if temp^.name = 'T         ' then lookup := tail(head(alist))
  603.     else lookup := lookup(key, tail(alist))
  604.   end;  { lookup }
  605.  
  606.   function bindargs(names, values : symbexpptr) : symbexpptr;
  607.  
  608.   var
  609.     temp, temp2 : symbexpptr;
  610.  
  611.   begin
  612.     if names^.anatom and (names^.name = 'NIL       ')
  613.     then bindargs := alist
  614.     else
  615.       begin
  616.         temp := cons(head(names), eval(head(values), alist));
  617.         temp2 := bindargs(tail(names), tail(values));
  618.         bindargs := cons(temp, temp2)
  619.       end
  620.   end; { bindargs }
  621.  
  622.   function evcon(condpairs : symbexpptr) : symbexpptr;
  623.  
  624.   var
  625.     temp : symbexpptr;
  626.  
  627.   begin
  628.     temp := eval(head(head(condpairs)), alist);
  629.     if temp^.anatom and (temp^.name = 'NIL       ')
  630.        then evcon := evcon(tail(condpairs))
  631.        else evcon := eval(head(tail(head(condpairs))), alist)
  632.   end; { evcon }
  633.  
  634. begin {        e v a l        }
  635.   if e^.anatom then eval := lookup(e, alist)
  636.   else begin
  637.      carofe := head(e);
  638.      if carofe^.anatom then
  639.         if not carofe^.isareservedword then
  640.           eval := eval(cons(lookup(carofe, alist), tail(e)), alist)
  641.         else
  642.           case carofe^.ressym of
  643.             labelsym,
  644.             lambdasym   : error(3);
  645.             quotesym    : eval := head(    tail(e)                         );
  646.             atomsym     : eval := atom(    eval(head(tail(e)),       alist));
  647.             eqsym       : eval := eqq(     eval(head(tail(e)),       alist),
  648.                                            eval(head(tail(tail(e))), alist));
  649.             headsym     : eval := head(    eval(head(tail(e)),       alist));
  650.             tailsym     : eval := tail(    eval(head(tail(e)),       alist));
  651.             conssym     : eval := cons(    eval(head(tail(e)),       alist),
  652.                                            eval(head(tail(tail(e))), alist));
  653.             condsym     : eval := evcon(   tail(e)                         );
  654.             appendsym   : eval := append(  eval(head(tail(e)),       alist),
  655.                                            eval(head(tail(tail(e))), alist));
  656.             replacehsym : eval := replaceh(eval(head(tail(e)),       alist),
  657.                                            eval(head(tail(tail(e))), alist));
  658.             replacetsym : eval := replacet(eval(head(tail(e)),       alist),
  659.                                            eval(head(tail(tail(e))), alist));
  660.          end  { case }
  661.        else
  662.          begin
  663.            caarofe := head(carofe);
  664.            if caarofe^.anatom and caarofe^.isareservedword then
  665.              if not (caarofe^.ressym in [labelsym, lambdasym]) then error(12)
  666.              else
  667.                case caarofe^.ressym of
  668.                  labelsym :
  669.                    begin
  670.                      temp := cons(cons(head(tail(carofe)),
  671.                                        head(tail(tail(carofe)))), alist);
  672.                      eval := eval(cons(head(tail(tail(carofe))), tail(e)),temp)
  673.                     end;
  674.                  lambdasym :
  675.                    begin
  676.                      temp := bindargs(head(tail(carofe)), tail(e));
  677.                      eval := eval(head(tail(tail(carofe))), temp)
  678.                    end
  679.                 end  { case }
  680.               else
  681.                 eval := eval(cons(eval(carofe, alist), tail(e)), alist)
  682.             end
  683.           end
  684.   end; { e v a l }
  685.  
  686. procedure initialize;
  687.  
  688. var
  689.   i            : integer;
  690.   temp,
  691.   nxt          : symbexpptr;
  692.  
  693. begin
  694.   alreadypeeked := false;
  695.   curline := '';
  696.   getch(ch);
  697.   numberofgcs := 0;
  698.   freenodes := maxnode;
  699.   with nilnode do begin
  700.       anatom := true;
  701.       next := nil;
  702.       name := 'NIL       ';
  703.       status := unmarked;
  704.       isareservedword := false
  705.   end;
  706.   with tnode do begin
  707.       anatom := true;
  708.       next := nil;
  709.       name := 'T         ';
  710.       status := unmarked;
  711.       isareservedword := false
  712.   end;
  713.  
  714. { - - - - allocate storage and mark it free  }
  715.  
  716.   freelist := nil;
  717.   for i := 1 to maxnode do begin
  718.       new(nodelist);
  719.       nodelist^.next := freelist;
  720.       nodelist^.head := freelist;
  721.       nodelist^.status := unmarked;
  722.       freelist := nodelist;
  723.   end;
  724.  
  725. { - - - -  initialize reserved word table }
  726.  
  727.   reswords[replacehsym] := 'REPLACEH  ';
  728.   reswords[replacetsym] := 'REPLACET  ';
  729.   reswords[headsym]     := 'CAR       ';
  730.   reswords[tailsym]     := 'CDR       ';
  731.   reswords[copysym]     := 'COPY      ';
  732.   reswords[appendsym]   := 'APPEND    ';
  733.   reswords[concsym]     := 'CONC      ';
  734.   reswords[conssym]     := 'CONS      ';
  735.   reswords[eqsym]       := 'EQ        ';
  736.   reswords[quotesym]    := 'QUOTE     ';
  737.   reswords[atomsym]     := 'ATOM      ';
  738.   reswords[condsym]     := 'COND      ';
  739.   reswords[labelsym]    := 'LABEL     ';
  740.   reswords[lambdasym]   := 'LAMBDA    ';
  741.  
  742. { - - - -  initialize the a-list with t and nil  }
  743.  
  744.   pop(alist);
  745.   alist^.anatom := false;
  746.   alist^.status := unmarked;
  747.   pop(alist^.tail);
  748.   nxt := alist^.tail^.next;
  749.   alist^.tail^ := nilnode;
  750.   alist^.tail^.next := nxt;
  751.   pop(alist^.head);
  752.  
  753. { - - - -  bind nil to the atom nil  }
  754.  
  755.   with alist^.head^ do begin
  756.       anatom := false;
  757.       status := unmarked;
  758.       pop(head);
  759.       nxt := head^.next;
  760.       head^ := nilnode;
  761.       head^.next := nxt;
  762.       pop(tail);
  763.       nxt := tail^.next;
  764.       tail^ := nilnode;
  765.       tail^.next := nxt
  766.   end;
  767.   pop(temp);
  768.   temp^.anatom := false;
  769.   temp^.status := unmarked;
  770.   temp^.tail := alist;
  771.   alist := temp;
  772.   pop(alist^.head);
  773.  
  774. { - - - - bind t to the atom t }
  775.  
  776.   with alist^.head^ do begin
  777.       anatom := false;
  778.       status := unmarked;
  779.       pop(head);
  780.       nxt := head^.next;
  781.       head^ := tnode;
  782.       head^.next := nxt;
  783.       pop(tail);
  784.       nxt := tail^.next;
  785.       tail^ := tnode;
  786.       tail^.next := nxt
  787.   end;
  788. end; { initialize }
  789.  
  790. { >>>>>>>>>>>>>>>  l i s p  <<<<<<<<<<<<<<<< }
  791.  
  792. begin
  793.   writeln(' * EVAL * ');
  794.   initialize;
  795.   nextsym;
  796.   readexpr(ptr);
  797.   while not ptr^.anatom or (ptr^.name <> 'FIN       ') do begin
  798.       writeln;
  799.       writeln(' * Value * ');
  800.       printexpr(eval(ptr, alist));
  801.       writeln;
  802.       writeln;
  803.       ptr := nil;
  804.       garbageman;
  805.       writeln;
  806.       writeln;
  807.       writeln(' * EVAL * ');
  808.       nextsym;
  809.       readexpr(ptr);
  810.       writeln;
  811.   end;
  812.   writeln;
  813.   writeln;
  814.   writeln(' Total number of garbage collections = ', numberofgcs:1,'.');
  815.   writeln;
  816.   writeln(' Free nodes left upon exit = ', freenodes:1,'.');
  817.   writeln;
  818. end. { lisp }
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825.  
  826.  
  827.  
  828. '.');
  829.   writeln;
  830.   writeln(' Free nodes left upon exit = ', freenodes:1,'.');
  831.   write